#if ENABLE_CROSS_DEVICE_BUILD
#if !defined(SHM_CACHELINE_BYTES) || !defined(SHM_MESG_SIZE)
#error "please define SHM_CACHELINE_BYTES and SHM_MESG_SIZE before include this header"
#endif
#endif

#ifndef __aligned
#define __aligned(x)                    __attribute__((__aligned__(x)))
#endif

#ifndef typecheck \
/*
 * Check at compile time that something is of a particular type.
 * Always evaluates to 1 so you may use it easily in comparisons.
 */
#define typecheck(type,x) \
({	type __dummy; \
	typeof(x) __dummy2; \
	(void)(&__dummy == &__dummy2); \
	1; \
})
#endif

/**
 * struct __xfifo - like struct __kfifo
 * @mask:       mask = (size - 1), size = 2^n, the unit is bytes
 * @esize:      size of element
 * @data_offset:data_offset = data_addr - __xfifo base addr
 * @out:        offset by bytes
 * @pad:        force out and in two cachelines
 * @in:         offset by bytes
 */
struct __xfifo {
    uint32_t mask;
    uint32_t esize;
#if ENABLE_CROSS_DEVICE_BUILD
    int32_t data_offset;
#else
    void *data;
#endif
    uint32_t in;
#if ENABLE_CROSS_DEVICE_BUILD
    struct {
        char __pad[0];
    } pad __aligned(SHM_CACHELINE_BYTES);
#endif
    uint32_t out;
}
#if ENABLE_CROSS_DEVICE_BUILD
__aligned(SHM_CACHELINE_BYTES) __packed
#endif
;

#define SHM_MESG_RECEIVER(mesg) \
	(typecheck(struct __xmesg *, mesg), (((mesg)->header >> 16) & 0xFF))
#define SHM_MESG_SENDER(mesg) \
	(typecheck(struct __xmesg *, mesg), (((mesg)->header >> 8) & 0xFF))
#define SHM_MESG_TYPE(mesg) \
	(typecheck(struct __xmesg *, mesg), ((mesg)->header & 0xFF))
#define SHM_MESG_DATA(mesg) \
	(typecheck(struct __xmesg *, mesg), ((void *)((mesg)->data)))

#define SHM_MESG_MAKE_HEADER(receiver, sender, type) \
    (((uint8_t)(receiver) << 16) \
    | ((uint8_t)(sender) << 8) \
    | ((type) & 0xFF))

/**
 * struct _-xmesg - common message structure
 * @header:		see SHM_MESG_MAKE_HEADER()
 * @reserved:	make sure __xmesg.data padding to 8bytes
 * @data:		message data, must use __packed if use as a structure
 */
struct __xmesg {
    uint32_t header;
    uint32_t reserved;
    char data[__XMESG_SIZE - 2 * sizeof(uint32_t)];
}
#if ENABLE_CROSS_DEVICE_BUILD
__aligned(SHM_CACHELINE_BYTES) __packed
#endif
;

#define SHM_MESG_RECEIVER(mesg) \
	(typecheck(struct __xmesg *, mesg), (((mesg)->header >> 16) & 0xFF))
#define SHM_MESG_SENDER(mesg) \
	(typecheck(struct __xmesg *, mesg), (((mesg)->header >> 8) & 0xFF))
#define SHM_MESG_TYPE(mesg) \
	(typecheck(struct __xmesg *, mesg), ((mesg)->header & 0xFF))
#define SHM_MESG_DATA(mesg) \
	(typecheck(struct __xmesg *, mesg), ((void *)((mesg)->data)))

#define SHM_MESG_MAKE_HEADER(receiver, sender, type) \
    (((uint8_t)(receiver) << 16) \
    | ((uint8_t)(sender) << 8) \
    | ((type) & 0xFF))

typedef int (*XMESG(handler_t))(struct __xmesg *mesg, void *data);


static inline void XMESG(init_header)(struct __xmesg *mesg,
                                      uint8_t receiver, uint8_t sender, uint8_t type)
{
    mesg->header = SHM_MESG_MAKE_HEADER(receiver, sender, type);
}

